#pragma once

#include "../mqcommon/log.hpp"
#include "../mqcommon/msg.pb.h"

#include <iostream>
#include <mutex>
#include <memory>
#include <vector>
#include <functional>

namespace mymq
{
    struct Consumer
    {
        using CallBack = std::function<void(const std::string&, const BasicProperties *bp, const std::string&)>;
        using ptr = std::shared_ptr<Consumer>;
        std::string tag;   // 消费者标识
        std::string qname; // 消费者订阅的队列名称
        bool auto_ack;     // 自动确认标志
        CallBack callback;
        Consumer(const std::string &ctag, const std::string &queue_name, bool ack_flag, const CallBack &cb)
            : tag(ctag), qname(queue_name), auto_ack(ack_flag), callback(cb)
        {
            DEBUG_LOG("new Consumer:%p", this);
        }
        Consumer()
        {
            DEBUG_LOG("new Consumer:%p", this);
        }
        ~Consumer()
        {
            DEBUG_LOG("del Consumer:%p", this);
        }
    };

    // 以队列为单元的消费者管理结构
    class QueueConsumer
    {
    public:
        using ptr = std::shared_ptr<QueueConsumer>;

    public:
        QueueConsumer(const std::string qname)
            : _qname(qname), _rr_seq(0)
        {
        }
        Consumer::ptr Create(const std::string &ctag, const std::string &queue_name,
                             bool ack_flag, const Consumer::CallBack &cb)
        {
            std::lock_guard<std::mutex> lock(_mtx);
            for (const auto &consumer : _consumers)
            {
                if (consumer->tag == ctag) // 找到了
                    return consumer;
            }
            Consumer::ptr cp = std::make_shared<Consumer>(ctag, queue_name, ack_flag, cb);
            _consumers.emplace_back(cp);
            return cp;
        }
        void Remove(const std::string &ctag)
        {
            std::lock_guard<std::mutex> lock(_mtx);
            for (auto it = _consumers.begin(); it != _consumers.end(); it++)
            {
                if ((*it)->tag == ctag) // 找到了
                {
                    _consumers.erase(it);
                    return;
                }
            }
        }
        Consumer::ptr Choose()
        {
            std::lock_guard<std::mutex> lock(_mtx);
            size_t size = _consumers.size();
            if (size == 0)
                return Consumer::ptr();
            uint64_t idx = _rr_seq % size;
            _rr_seq++;
            return _consumers[idx];
        }
        bool Empty()
        {
            std::lock_guard<std::mutex> lock(_mtx);
            return _consumers.size() == 0;
        }
        bool Exists(const std::string &ctag)
        {
            std::lock_guard<std::mutex> lock(_mtx);
            for (const auto &consumer : _consumers)
            {
                if (consumer->tag == ctag) // 找到了
                    return true;
            }
            return false;
        }
        void Clear()
        {
            std::lock_guard<std::mutex> lock(_mtx);
            _consumers.clear();
            _rr_seq = 0;
        }

    private:
        std::mutex _mtx;
        std::string _qname;
        uint64_t _rr_seq; // 轮转序号
        std::vector<Consumer::ptr> _consumers;
    };

    class ConsumerManager
    {
    public:
        using ptr = std::shared_ptr<ConsumerManager>;

    public:
        ConsumerManager() {}
        void InitQueueConsumer(const std::string &qname)
        {
            std::lock_guard<std::mutex> lock(_mtx);
            auto it = _qconsumers.find(qname);
            if (it != _qconsumers.end())
            {
                INFO_LOG("创建以队列为单元管理的消费者句柄%s失败", qname.c_str());
                return;
            }
            QueueConsumer::ptr qp = std::make_shared<QueueConsumer>(qname);
            _qconsumers.insert(std::make_pair(qname, qp));
        }
        void DestroyQueueConsumer(const std::string &qname)
        {
            std::lock_guard<std::mutex> lock(_mtx);
            auto it = _qconsumers.find(qname);
            if (it == _qconsumers.end())
            {
                INFO_LOG("删除以队列为单元管理的消费者句柄%s失败", qname.c_str());
                return;
            }
            _qconsumers.erase(qname);
        }
        Consumer::ptr Create(const std::string &ctag, const std::string &qname,
                             bool ack_flag, const Consumer::CallBack &cb)
        {
            QueueConsumer::ptr qp;
            {
                std::lock_guard<std::mutex> lock(_mtx);
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    INFO_LOG("没有找到队列 %s 的消费者管理句柄！创建消费者%s失败", qname.c_str(), ctag.c_str());
                    return Consumer::ptr();
                }
                qp = it->second;
            }
            return qp->Create(ctag, qname, ack_flag, cb);
        }
        void Remove(const std::string &tag, const std::string &qname)
        {
            QueueConsumer::ptr qp;
            {
                std::lock_guard<std::mutex> lock(_mtx);
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    INFO_LOG("没有找到队列 %s 的消费者管理句柄！删除消费者%s失败", qname.c_str(), tag.c_str());
                    return;
                }
                qp = it->second;
            }
            return qp->Remove(tag);
        }
        Consumer::ptr Choose(const std::string &qname)
        {
            QueueConsumer::ptr qp;
            {
                std::lock_guard<std::mutex> lock(_mtx);
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    INFO_LOG("没有找到队列 %s 的消费者管理句柄！获取消费者失败", qname.c_str());
                    return Consumer::ptr();
                }
                qp = it->second;
            }
            return qp->Choose();
        }
        bool Empty(const std::string &qname)
        {
            QueueConsumer::ptr qp;
            {
                std::lock_guard<std::mutex> lock(_mtx);
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    INFO_LOG("没有找到队列 %s 的消费者管理句柄！判断其中消费者是否为空失败", qname.c_str());
                    return false;
                }
                qp = it->second;
            }
            return qp->Empty();
        }
        bool Exists(const std::string &ctag, const std::string &qname)
        {
            QueueConsumer::ptr qp;
            {
                std::lock_guard<std::mutex> lock(_mtx);
                auto it = _qconsumers.find(qname);
                if (it == _qconsumers.end())
                {
                    INFO_LOG("没有找到队列 %s 的消费者管理句柄！判断其中消费者%s是否存在失败", qname.c_str(), ctag.c_str());
                    return false;
                }
                qp = it->second;
            }
            return qp->Exists(ctag);
        }
        void Clear()
        {
            std::lock_guard<std::mutex> lock(_mtx);
            _qconsumers.clear();
        }
    private:
        std::mutex _mtx;
        std::unordered_map<std::string, QueueConsumer::ptr> _qconsumers;
    };
}